package com.why.cachecloud.service.inspect.impl;

import com.why.cachecloud.service.alert.impl.BaseAlertService;
import com.why.cachecloud.dao.AppDao;
import com.why.cachecloud.entity.AppDesc;
import com.why.cachecloud.entity.InstanceInfo;
import com.why.cachecloud.entity.InstanceStats;
import com.why.cachecloud.service.inspect.InspectParamEnum;
import com.why.cachecloud.service.inspect.Inspector;
import com.why.cachecloud.service.stats.app.AppStatsCenter;
import com.why.cachecloud.service.stats.instance.InstanceStatsCenter;
import com.why.cachecloud.util.ConstUtils;
import com.why.cachecloud.util.TypeUtil;
import com.why.cachecloud.web.vo.AppDetailVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by why.developer on 15-1-20.
 */
@Component
public class AppMemInspector extends BaseAlertService implements Inspector {

    /**
     * app统计相关
     */
    @Resource
    private AppStatsCenter appStatsCenter;

    /**
     * 应用相关dao
     */
    @Resource
    private AppDao appDao;

    /**
     * 实例统计相关
     */
    @Resource
    private InstanceStatsCenter instanceStatsCenter;

    @Override
    public boolean inspect(Map<InspectParamEnum, Object> paramMap) {
        Long appId = MapUtils.getLong(paramMap, InspectParamEnum.SPLIT_KEY);
        List<AppDesc> appDescList = new ArrayList<AppDesc>();
        AppDesc app = appDao.getAppDescById(appId);
        if (app != null) {
            appDescList.add(app);
        }
        if (CollectionUtils.isEmpty(appDescList)) {
            logger.warn("appList is empty, appId={}", appId);
            return true;
        }
        for (AppDesc appDesc : appDescList) {
            //测试不检查
            if (appDesc.getIsTest() == 1) {
                continue;
            }
            long checkAppId = appDesc.getAppId();
            AppDetailVO appDetailVO = appStatsCenter.getAppDetail(checkAppId);
            if (appDetailVO == null) {
                continue;
            }
            double appMemUsePercent = appDetailVO.getMemUsePercent();
            int appUseSetMemAlertValue = appDesc.getMemAlertValue();
            int appUseSetMemAlertValueMin = appDesc.getMemAlertValueMin();
            // 先检查应用的内存使用率是否超过阀值，如果没有再检查分片
            if (appMemUsePercent > appUseSetMemAlertValue) {
                // 报警
                alertAppMemUse(appDetailVO, "max");
            } else if (appMemUsePercent < appUseSetMemAlertValueMin) {
                alertAppMemUse(appDetailVO, "min");
            } else {
                List<InstanceInfo> appInstanceInfoList = (List<InstanceInfo>) paramMap.get(InspectParamEnum.INSTANCE_LIST);
                if (CollectionUtils.isNotEmpty(appInstanceInfoList)) {
                    for (InstanceInfo instanceInfo : appInstanceInfoList) {
                        if (instanceInfo == null) {
                            continue;
                        }
                        if (!TypeUtil.isRedisType(instanceInfo.getType())) {
                            continue;
                        }
                        // 忽略sentinel观察者
                        if (TypeUtil.isRedisSentinel(instanceInfo.getType())) {
                            continue;
                        }
                        long instanceId = instanceInfo.getId();
                        InstanceStats instanceStats = instanceStatsCenter.getInstanceStats(instanceId);
                        if (instanceStats == null) {
                            continue;
                        }
                        double instanceMemUsePercent = instanceStats.getMemUsePercent();
                        // 大于标准值
                        if (instanceMemUsePercent > appUseSetMemAlertValue) {
                            alertInstanceMemUse(instanceStats, appDetailVO, "max");
                        } else if (instanceMemUsePercent < appUseSetMemAlertValueMin) {
                            alertInstanceMemUse(instanceStats, appDetailVO, "min");
                        }
                    }
                }
            }
        }
        return true;
    }

    /**
     * @param appDetailVO
     */
    private void alertAppMemUse(final AppDetailVO appDetailVO, String type) {
        AppDesc appDesc = appDetailVO.getAppDesc();
        List<String> mobileList = appDetailVO.getMobileList();
        boolean isMin = "min".equals(type);
        String content = String.format("#### 应用内存使用率报警 " + ConstUtils.getPhoneString(mobileList) + " \n\n 应用id：%s \n\n 应用名：%s \n\n 告警内容：内存使用率%s阈值 \n\n 告警值：%s%% \n\n 检测值：%s%%",
                appDesc.getAppId(), appDesc.getName(), isMin ? "低于" : "高于", isMin ? appDesc.getMemAlertValueMin() : appDesc.getMemAlertValue(), appDetailVO.getMemUsePercent());
        dingTalkComponent.sendDingTalkToAll(content, mobileList);

    }

    private void alertInstanceMemUse(final InstanceStats instanceStats, final AppDetailVO appDetailVO, String type) {
        String instanceInfo = instanceStats.getIp() + ":" + instanceStats.getPort();
        List<String> mobileList = appDetailVO.getMobileList();
        boolean isMin = "min".equals(type);
        AppDesc appDesc = appDetailVO.getAppDesc();
        String content = String.format("#### 分片内存使用率报警 " + ConstUtils.getPhoneString(mobileList) + " \n\n 分片信息：%s \n\n 应用id：%s \n\n 应用名：%s \n\n 告警内容：内存使用率%s阈值 \n\n 告警值：%s%% \n\n 检测值：%s%% \n\n 应用的内存使用率：%s%%",
                instanceInfo, instanceStats.getAppId(), appDesc.getName(),
                isMin ? "低于" : "高于",
                isMin ? appDesc.getMemAlertValueMin() : appDesc.getMemAlertValue(),
                instanceStats.getMemUsePercent(), appDetailVO.getMemUsePercent());
        dingTalkComponent.sendDingTalkToAll(content, mobileList);
    }

    public void setAppStatsCenter(AppStatsCenter appStatsCenter) {
        this.appStatsCenter = appStatsCenter;
    }

    public void setAppDao(AppDao appDao) {
        this.appDao = appDao;
    }

    public void setInstanceStatsCenter(InstanceStatsCenter instanceStatsCenter) {
        this.instanceStatsCenter = instanceStatsCenter;
    }

}
